home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
oper_sys
/
presto
/
prest1_0.lha
/
src
/
callstate.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-12-11
|
9KB
|
356 lines
/*
* callstate.c
*
* Machine dependent code to remember and restore the callstate
* so that we can "squirrel" away a user's function call and make it
* later.
*
*
* Last modified: 12/21/87
* by: bnb
* reason: make preempt safe by updating sp before
* copy args gets done, rather than after.
*
* Chase 8/1/88 added vax code
*/
#define _CALLSTATE_C
#include "presto.h"
#ifdef sun
private_t long _fctaddr;
#ifdef mc68020
//
// nargs.c -- Jim and Janet Carson, 12/27/88 @ 1:04am CST
//
// Implementation of C-callable get-number-arguments function
// for the motorola 680x0 series microprocessors.
// I suppose this should be inline...
//
// This function is dedicated to the poor students of Comp 320,
// Spring 1989, who had this as a question on their open-book
// final exam.
//
static int _ipc; /* program counter = address of next instruction */
static short _instr; /* instruction at ipc */
#define ADDQW1 0x584f
#define ADDQW2 0x504f
#define LEA 0x4fef
int nargs()
{
asm("movl a6, sp@- "); // 1. Save the frame pointer.
asm("movl a6@, a6 "); // 2. Trace back one frame -- not to
// the routine that called nargs(),
// but to the routine that called the
// routine that called nargs().
asm("movl a6@(4), __ipc "); // 3. Get the return address
asm("movl sp@+, a6 "); // 4. Restore the frame pointer
_instr = *((short *) _ipc); // 5. Get the next instruction after the
// return address. The next
// instruction is one of the following:
if (_instr == ADDQW1) // a. addql #4. There was ONE argument.
return(1);
else if (_instr == ADDQW2) // b. addql #8. There were TWO arguments.
return(2);
else if ( _instr == LEA) // c. lea sp@(JJ), sp. (where JJ is the
// short word following the lea instr.)
// There were JJ/4 arguments.
return ((int)(*(((short *)_ipc)+1))/4);
else // d. Something else. There were NO
return(0); // arguments.
}
#endif /* mc68020 */
#endif /* sun */
#ifdef vax
//
// Caller's saved AP points to the number of args for caller.
// Could be an inline asm.
//
int
nargs()
{
asm("movl *8(fp), r0");
}
#endif
//
// Callstate set called with:
// pointer to function to be called later on
// number of args (longwords) it should get called with
// a pointer to the base of those args
//
// We store this information away and later shove it on to the call
// stack of the function we want to call.
//
Callstate::~Callstate()
{
#ifdef mips
#else
if (cs_argvd)
delete cs_argvd;
#endif
}
//
// Copy the arglist into the callstate.
// If there are args,
// and the # args > size of cs space, then
// delete the existing dynamic cs space
// make some new ones
// record size of new cs space
// copy args into new dynamic space
// else, have enough room somewhere. Copy args
// into dynamic space (if we have it), else into
// static area.
//
// For the vax, we need to make sure we have two words at the front
// of the cs_argvd block for the arg count and "this" argument. See
// comments in Callstate::call below.
//
#ifdef mips
void
Callstate::set(PFany f, Objany arg)
{
cs_func = f;
cs_arg = arg;
}
void
Callstate::call(int *sp, Objany obj)
{
Objany local;
thisthread->andstate(~TS_VIRGIN);
if (obj)
local = ((PFRany)cs_func)(obj, cs_arg);
else
local = ((PFRany)cs_func)(cs_arg);
thisthread->terminate((Objany)local);
//
// NOT REACHED!
//
sp = sp;
}
#else /* !mips */
void
Callstate::set(PFany f, int argc, int *argv)
{
register int *ap;
cs_func = f;
cs_argc = argc;
if (argc) {
if (argc > cs_len) {
delete cs_argvd;
#ifdef vax
cs_argvd = new int [argc+2];
ap = &cs_argvd[2];
#else
cs_argvd = new int [argc];
ap = cs_argvd;
#endif
cs_len = cs_argc;
} else {
#ifdef vax
ap = (cs_argvd) ? &cs_argvd[2] : cs_argvs;
#else
ap = (cs_argvd) ? cs_argvd : cs_argvs;
#endif
}
bcopy((char*)argv, (char*)ap, argc * sizeof(int));
}
}
//
// Perform the actual call.
//
// WARNING (for sequent ns32000 version):
// if the routine we are calling tries to do an nargs
// its gonna get the wrong answer (0) since we wont
// have an constant in the adjspb field after the jsr r0
// 'cest la vie...
//
//
//
void
Callstate::call(int *sp, Objany obj)
{
int local = 0;
#ifdef sun
int func = (int)cs_func;
#else
int *func = (int *)cs_func;
#endif /* sun */
int stackbytes = cs_argc * sizeof(long);
#ifdef vax
//
// We want to use CALLG to avoid copying the args onto the stack.
// This is weird...we need a contiguous block of longwords containing
// the arg count followed by the arguments. We have to play some games
// since the arguments may be in the callstate struct itself or they
// may be in the allocated block pointed to by cs_argvd. If they are
// in a cs_argvd block, the block will have two extra words at the top
// for the arg count and the "this" argument.
//
register int *ap; // ptr to arg block for callg
if (cs_argvd)
ap = cs_argvd;
else
ap = &cs_argc;
//
// Hack to properly handle "this" argument with callg. Yuck.
//
if (obj) {
ap[0] = ++cs_argc;
ap[1] = (int)obj;
} else {
ap++;
*ap = cs_argc; // gag
}
local = (int)ap;
thisthread->andstate(~TS_VIRGIN); // XXX WINDOW?
asm("callg *-4(fp), *-8(fp)");
asm("movl r0, -4(fp)");
#endif /* vax */
#if (sequent || sun)
//
// can just toss the args right onto the stack, and do the
// call ourselves. Remember to adjust the sp correctly
// once the call returns
//
if (sp == 0) { // figure it out for ourselves
#ifdef ns32000
asm("sprd sp, -4(fp)");
#endif
#ifdef i386
asm("movl %esp, -4(%ebp)");
#endif
#ifdef mc68020
asm("movl sp, a6@(-4)");
#endif /* mc68020 */
sp = (int*)local;
}
//
// Copy argv from callstate into stack for callee
// Can't use bcopy here cuz we would be copying over our actual
// stack.
//
if (cs_argc) {
register int *s = cs_argvd ? (cs_argvd) : (cs_argvs);
register int *d = (int*)(sp - cs_argc);
//
// update where we the sp is before we start
// writing into the stack. Save ourselves from async
// interrupts.
//
local = (int)(sp - cs_argc);
#ifdef ns32000
asm("lprd sp, -4(fp)"); // sp = local
#endif
#ifdef i386
asm("movl -4(%ebp), %esp"); // sp = local
#endif
#ifdef mc68020
asm("movl a6@(-4), sp"); // sp = local;
#endif /* mc68020 */
while (d != sp)
*d++ = *s++;
}
if (obj) {
// shove hidden first argument "this"
local = (int)obj;
#ifdef ns32000
asm("movd -4(fp), tos"); // sp-- = local
#endif
#ifdef i386
asm("pushl -4(%ebp)"); // sp-- = local
#endif
#ifdef mc68020
asm("movl a6@(-4), sp@-"); // sp-- = local
#endif /* mc68020 */
}
// remember the byte count so we can undo it when func returns
if (obj)
local = -(stackbytes + sizeof(Objany)); // (-4(fp))
else
local = -stackbytes;
//
// Safe to preempt now that stack has been set
//
thisthread->andstate(~TS_VIRGIN);
//
// Call intended function and return anything left over in r0.
//
#ifdef mc68020
asm("movl a6@(-8), __fctaddr " ); // a0 = func
asm("jsr __fctaddr@ " ); // call func
asm("addql #4, sp "); // up sp count
asm("movl d0, a6@(-4) " ); // local = d0
#endif /* mc68020 */
#ifdef ns32000
asm("movd -8(fp), r0"); // r0 = func
asm("jsr r0"); // call
asm("adjspb -4(fp)"); // up sp count
asm("movd r0, -4(fp)"); // local = r0;
#endif
#ifdef i386
asm("call *-8(%ebp)"); // call func
asm("popl %ecx"); // up sp count
asm("movl %eax, -4(%ebp)"); // local = return value
#endif
#endif /* sequent */
thisthread->terminate((Objany)local);
//
// NOT REACHED!
//
}
#endif /* mips */
void
Callstate::print(ostream& s)
{
#ifdef mips
s << form("(Callstate)this=0x%x, cs_func=0x%x, cs_arg=0x%x",
this, cs_func, cs_arg);
#else
s << form("(Callstate)this=0x%x, cs_func=0x%x, cs_argc=0x%x, cs_argvs=0x%x, cs_argvd=0x%x",
this, cs_func, cs_argc, cs_argvs, cs_argvd);
#endif
}
ostream& operator<<(ostream& s, Callstate& c)
{
c.print(s);
return s;
}